/*
 * @(#)Downloader.java   09/10/26
 *
 * Copyright (c) 2009 HKUST. All rights reserved.
 *
 */

package org.ust.downloader;

//~--- non-JDK imports --------------------------------------------------------

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

/**
 * Class description
 * 
 * 
 * @version 0.1, 09/10/26
 * @author Nelson LAU
 */
public class Downloader
{
	private File	apiDir;
	private String	dirName;
	private String	link;

	/**
	 * Constructs ...
	 * 
	 * 
	 * @param link
	 * @param apiDirStr
	 */
	public Downloader ( String link , String apiDirStr )
	{
		apiDir = null;
		this.link = link;
		this.dirName = apiDirStr;
	}

	/**
	 * Method description
	 * 
	 * @param shouldAbortLock
	 * 
	 * 
	 * @throws CannotCreateFolderException
	 */
	public void beginDownload ( NavigationLock shouldAbortLock )
			throws CannotCreateFolderException
	{
		// if (System.getProperty("os.name").contains("Mac"))
		// {
		String downloadFileStr = link.substring ( link.lastIndexOf ( "/" ) + 1 ,
				link.indexOf ( "?" ) );

		if ( apiDir == null )
		{
			apiDir = new File ( System.getProperty ( "user.dir" ) + "/"
					+ dirName );

			if ( ! apiDir.exists ( ) )
			{
				apiDir.mkdir ( );
			}
		}

		File downloadFile = new File ( apiDir + "/" + downloadFileStr );

		if ( ! downloadFile.exists ( ) )
		{
			try
			{
				URL url = new URL ( link );
				URLConnection conn = url.openConnection ( );
				BufferedReader reader = new BufferedReader (
						new InputStreamReader ( conn.getInputStream ( ) ) );
				BufferedWriter writer = new BufferedWriter ( new FileWriter (
						downloadFile ) );

				int c;

				while ( ( c = reader.read ( ) ) != - 1 )
				{
					synchronized ( shouldAbortLock )
					{
						if ( shouldAbortLock.isAbort ( ) )
						{
							throw new IOException ( "Download period exceeded "
									+ shouldAbortLock
											.getMaxPausePeriodInSecond ( )
									+ " for " + downloadFileStr + "." );
						}
					}

					writer.write ( c );
				}

				System.out.println ( "Downloading " + downloadFileStr
						+ " finished." );

				synchronized ( shouldAbortLock )
				{
					shouldAbortLock.setFinished ( true );
				}
			}
			catch ( MalformedURLException e )
			{
				e.printStackTrace ( );
			}
			catch ( IOException e )
			{
				e.printStackTrace ( );
			}

			// download ( apiDir + "/" + downloadFileStr , link ,
			// downloadFileStr ,
			// shouldAbortLock );
		}
		else
		{
			synchronized ( shouldAbortLock )
			{
				// if (shouldAbortLock.isAbort() == false)
				// {
				System.out.println ( "Aborting downloading " + downloadFileStr
						+ " due to file existence" );
				shouldAbortLock.setFinished ( true );

				// }
			}
		}

		// }
		// else
		// {
		// JOptionPane.showMessageDialog(null, "Unsupported OS Platform.",
		// "Alert!",
		// JOptionPane.INFORMATION_MESSAGE);
		// }
	}

	private void download ( String fileName , String downloadPath ,
			String downloadedFileStr , NavigationLock shouldAbortLock )
			throws CannotCreateFolderException
	{
		DefaultHttpClient httpclient = null;
		BufferedReader reader = null;
		BufferedWriter writer = null;
		File downloadedFile = null;

		try
		{
			HttpHost target = new HttpHost ( "downloads.sourceforge.net" , 80 ,
					"http" );
			SchemeRegistry supportedSchemes = new SchemeRegistry ( );

			supportedSchemes.register ( new Scheme ( "http" ,
					PlainSocketFactory.getSocketFactory ( ) , 80 ) );

			HttpParams params = new BasicHttpParams ( );

			HttpProtocolParams.setVersion ( params , HttpVersion.HTTP_1_1 );
			HttpProtocolParams.setContentCharset ( params , "UTF-8" );
			HttpProtocolParams.setUseExpectContinue ( params , true );

			ClientConnectionManager connMgr = new ThreadSafeClientConnManager (
					params , supportedSchemes );

			httpclient = new DefaultHttpClient ( connMgr , params );

			int startIndex = downloadPath.indexOf ( "/project/" );
			String uriToDownloadFile = downloadPath.substring ( startIndex );
			URI pathToDowloadFile = new URI ( uriToDownloadFile );
			HttpGet req = new HttpGet ( pathToDowloadFile );

			System.out.println ( "Begin downloading " + fileName );

			HttpResponse response;

			response = httpclient.execute ( target , req );

			HttpEntity entity = response.getEntity ( );

			if ( entity != null )
			{
				reader = new BufferedReader ( new InputStreamReader ( entity
						.getContent ( ) ) );

				String pathName = System.getProperty ( "user.dir" ) + "/"
						+ dirName;
				File f = new File ( pathName );

				if ( f != null )
				{
					if ( ! f.exists ( ) )
					{
						if ( ! f.mkdir ( ) )
						{
							throw new CannotCreateFolderException (
									"Cannot create storing folder." );
						}
					}
				}

				downloadedFile = new File ( pathName + "/" + downloadedFileStr );

				if ( downloadedFile == null )
				{
					throw new FileNotFoundException (
							"Cannot create downloaded file." );
				}

				writer = new BufferedWriter ( new FileWriter ( downloadedFile ) );

				int c;

				while ( ( c = reader.read ( ) ) != - 1 )
				{
					synchronized ( shouldAbortLock )
					{
						if ( shouldAbortLock.isAbort ( ) )
						{
							throw new IOException ( "Download period exceeded "
									+ shouldAbortLock
											.getMaxPausePeriodInSecond ( )
									+ " for " + downloadedFileStr + "." );
						}
					}

					writer.write ( c );
				}

				System.out.println ( "Downloading " + downloadedFileStr
						+ " finished." );

				synchronized ( shouldAbortLock )
				{
					shouldAbortLock.setFinished ( true );
				}
			}
		}
		catch ( ClientProtocolException e )
		{
			System.out.println ( e.getMessage ( ) );
			System.out.println ( "Download goes on." );
		}
		catch ( URISyntaxException e )
		{
			System.out.println ( e.getMessage ( ) );
			System.out.println ( "Download goes on." );
		}
		catch ( IOException e )
		{
			System.out.println ( e.getMessage ( ) );

			if ( downloadedFile != null )
			{
				if ( downloadedFile.exists ( ) )
				{
					downloadedFile.delete ( );
				}
			}
		}

		closeAll ( httpclient , reader , writer );
	}

	private void closeAll ( DefaultHttpClient httpclient ,
			BufferedReader reader , BufferedWriter writer )
	{
		if ( reader != null )
		{
			try
			{
				reader.close ( );
			}
			catch ( IOException e )
			{
				e.printStackTrace ( );
			}
		}

		if ( writer != null )
		{
			try
			{
				writer.close ( );
			}
			catch ( IOException e )
			{
				e.printStackTrace ( );
			}
		}

		if ( httpclient != null )
		{
			httpclient.getConnectionManager ( ).shutdown ( );
		}
	}
}
